﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BrandUnion.CustomData
{
    public class BookingFactory : FactoryBase
    {
        public BookingFactory() { }
        public BookingFactory(DataContext context) : base(context) { }
        
        public List<Booking> GetAll()
        {
            var tmp = from b in Context.Bookings
                      join s in Context.BookingSlots on b.BookingSlotId equals s.Id where !s.Deleted 
                      join u in Context.Users on b.UserId equals u.Id into lu
                      from user in lu.DefaultIfEmpty()
                      orderby s.DateTime, b.Created
                      select new Booking(b, s.DateTime, user);
            return tmp.ToList();
        }

        public List<Booking> GetAllByBookingSlotId(int bookingSlotId)
        {
            var tmp = from b in Context.Bookings
                      join s in Context.BookingSlots on b.BookingSlotId equals s.Id
                      where !s.Deleted
                      join u in Context.Users on b.UserId equals u.Id into lu
                      from user in lu.DefaultIfEmpty()
                      where s.Id == bookingSlotId
                      orderby s.DateTime, b.Created
                      select new Booking(b, s.DateTime, user);
            return tmp.ToList();
        }

        public Booking GetByUserId(int userId)
        {
            var tmp = from b in Context.Bookings
                      where b.UserId == userId
                      join s in Context.BookingSlots on b.BookingSlotId equals s.Id
                      where !s.Deleted
                      join u in Context.Users on b.UserId equals u.Id into lu
                      from user in lu.DefaultIfEmpty()
                      select new Booking(b, s.DateTime, user);
            return tmp.SingleOrDefault();
        }

        public Booking GetById(int id)
        {
            var tmp = from b in Context.Bookings
                      where b.Id == id
                      join s in Context.BookingSlots on b.BookingSlotId equals s.Id
                      where !s.Deleted
                      join u in Context.Users on b.UserId equals u.Id into lu
                      from user in lu.DefaultIfEmpty()
                      select new Booking(b, s.DateTime, user);
            return tmp.SingleOrDefault();
        }

        public Booking GetByEmailAddress(string emailAddress)
        {
            var tmp = from b in Context.Bookings
                      where b.EmailAddress == emailAddress
                      join s in Context.BookingSlots on b.BookingSlotId equals s.Id
                      where !s.Deleted
                      join u in Context.Users on b.UserId equals u.Id into lu
                      from user in lu.DefaultIfEmpty()
                      select new Booking(b, s.DateTime, user);
            return tmp.FirstOrDefault();
        }

        public void Save(Booking booking)
        {
            Data.Booking tmp = null;
            if (booking.Id == 0)
            {
                tmp = new Data.Booking();
                tmp.Created = DateTime.UtcNow;
                Context.Bookings.InsertOnSubmit(tmp);
            }
            else
            {
                tmp = Context.Bookings.Where(x => x.Id == booking.Id).Single();
            }

            bool reloadTime = false;
            if (tmp.BookingSlotId != booking.BookingSlotId)
            {
                tmp.BookingSlotId = booking.BookingSlotId;
                reloadTime = true;
            }

            if (booking.UserId == null)
            {
                tmp.UserId = null;
                tmp.Address1 = booking.Address1;
                tmp.Address2 = booking.Address2;
                tmp.County = booking.County;
                tmp.EmailAddress = booking.EmailAddress;
                tmp.FirstName = booking.FirstName;
                tmp.Gender = (byte)booking.Gender;
                tmp.LastName = booking.LastName;
                tmp.MoreInfo = booking.MoreInfo;
                tmp.PostCode = booking.PostCode;
                tmp.Tel = booking.Tel;
                tmp.Town = booking.Town;
                tmp.Age = booking.Age;
            }
            else
            {
                tmp.UserId = booking.UserId;
                tmp.Address1 = null;
                tmp.Address2 = null;
                tmp.County = null;
                tmp.EmailAddress = null;
                tmp.FirstName = null;
                tmp.Gender = null;
                tmp.LastName = null;
                tmp.MoreInfo = false;
                tmp.PostCode = null;
                tmp.Tel = null;
                tmp.Town = null;
                tmp.Age = null;
            }
            Context.SubmitChanges();
            DateTime tmpDateTime = booking.DateTime;
            if (reloadTime)
            {
                tmpDateTime = tmp.BookingSlot.DateTime;
            }
            booking.SetData(tmp, tmpDateTime, tmp.UserId.HasValue ? Context.Users.Where(x => x.Id == tmp.UserId).SingleOrDefault() : null);
        }

        public void Delete(Booking booking)
        {
            Data.Booking tmp = Context.Bookings.Where(x => x.Id == booking.Id).Single();

            if (tmp != null)
            {
                Context.Bookings.DeleteOnSubmit(tmp);
                Context.SubmitChanges();
            }
        }
    }

    public class Booking
    {
        public Booking()
        {
        }

        public Booking(int userId) 
        {
            this.UserId = userId;
        }

        internal Booking(Data.Booking booking, DateTime dateTime, Data.User user) { SetData(booking, dateTime, user); }

        internal void SetData(Data.Booking booking, DateTime dateTime, Data.User user)
        {
            this.Id = booking.Id;
            this.BookingSlotId = booking.BookingSlotId;
            this.DateTime = dateTime;
            this.UserId = booking.UserId;
            this.Created = booking.Created.ToLocalTime();
            this.MoreInfo = booking.MoreInfo;
            if (user == null)
            {
                this._FirstName = booking.FirstName;
                this._LastName = booking.LastName;
                this._Address1 = booking.Address1;
                this._Address2 = booking.Address2;
                this._Town = booking.Town;
                this._County = booking.County;
                this._PostCode = booking.PostCode;
                this._EmailAddress = booking.EmailAddress;
                this._Tel = booking.Tel;
                this._Age = booking.Age;
                if (booking.Gender.HasValue)
                {
                    this._Gender = (Acms.Bll.User.Genders)booking.Gender.Value;
                }
            }
            else
            {
                this._FirstName = user.FirstName;
                this._LastName = user.LastName;
                this._Address1 = user.Address1;
                this._Address2 = user.Address2;
                this._Town = user.Town;
                this._County = user.County;
                this._PostCode = user.PostCode;
                this._EmailAddress = user.EmailAddress;
                this._Tel = user.MobileTel;
                int val = 0;
                if (user.DateOfBirth != null)
                {
                    val = dateTime.Year - user.DateOfBirth.Value.ToLocalTime().Year;
                    if (dateTime.Month < user.DateOfBirth.Value.ToLocalTime().Month || (dateTime.Month == user.DateOfBirth.Value.ToLocalTime().Month && dateTime.Day < user.DateOfBirth.Value.ToLocalTime().Day))
                    {
                        val--;
                    }
                }
                this._Age = val;
                if (user.Gender.HasValue)
                {
                    this._Gender = (Acms.Bll.User.Genders)user.Gender.Value;
                }
            }
        }

        public int Id { get; private set; }
        public int BookingSlotId { get; set; }
        public DateTime DateTime { get; private set; }
        public int? UserId { get; private set; }

        private string _FirstName;
        public string FirstName
        {
            get
            {
                return _FirstName;
            }
            set
            {
                if (UserId == null)
                {
                    _FirstName = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set FirstName property if user id is set");
                }
            }
        }

        private string _LastName;
        public string LastName
        {
            get
            {
                return _LastName;
            }
            set
            {
                if (UserId == null)
                {
                    _LastName = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set LastName property if user id is set");
                }
            }
        }

        private string _EmailAddress;
        public string EmailAddress
        {
            get
            {
                return _EmailAddress;
            }
            set
            {
                if (UserId == null)
                {
                    _EmailAddress = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set EmailAddress property if user id is set");
                }
            }
        }

        private string _Tel;
        public string Tel
        {
            get
            {
                return _Tel;
            }
            set
            {
                if (UserId == null)
                {
                    _Tel = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Tel property if user id is set");
                }
            }
        }

        private Acms.Bll.User.Genders _Gender;
        public Acms.Bll.User.Genders Gender
        {
            get
            {
                return _Gender;
            }
            set
            {
                if (UserId == null)
                {
                    _Gender = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Gender property if user id is set");
                }
            }
        }

        private string _Address1;
        public string Address1
        {
            get
            {
                return _Address1;
            }
            set
            {
                if (UserId == null)
                {
                    _Address1 = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Address1 property if user id is set");
                }
            }
        }

        private string _Address2;
        public string Address2
        {
            get
            {
                return _Address2;
            }
            set
            {
                if (UserId == null)
                {
                    _Address2 = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Address2 property if user id is set");
                }
            }
        }

        private string _Town;
        public string Town
        {
            get
            {
                return _Town;
            }
            set
            {
                if (UserId == null)
                {
                    _Town = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Town property if user id is set");
                }
            }
        }

        private string _County;
        public string County
        {
            get
            {
                return _County;
            }
            set
            {
                if (UserId == null)
                {
                    _County = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set County property if user id is set");
                }
            }
        }

        private string _PostCode;
        public string PostCode
        {
            get
            {
                return _PostCode;
            }
            set
            {
                if (UserId == null)
                {
                    _PostCode = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set PostCode property if user id is set");
                }
            }
        }

        private int? _Age;
        public int? Age
        {
            get
            {
                return _Age;
            }
            set
            {
                if (UserId == null)
                {
                    _Age = value;
                }
                else
                {
                    throw new ApplicationException("Cannot set Age property if user id is set");
                }
            }
        }


        public DateTime Created { get; private set; }
        public bool MoreInfo { get; set; }
    }
}
